package com.triplelink.dao.impl.openrdf;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openrdf.query.BindingSet;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;

import com.triplelink.annotations.Property;
import com.triplelink.builder.query.DeleteQueryBuilder;
import com.triplelink.builder.query.InsertQueryBuilder;
import com.triplelink.builder.query.MergeQueryBuilder;
import com.triplelink.builder.query.QueryTL;
import com.triplelink.business.impl.rush.EntityGeneretor;
import com.triplelink.context.Connector;
import com.triplelink.dao.interfaces.EntityDAO;
import com.triplelink.exception.TripleLinkException;

public class EntityDAOOpenrdf extends BaseDAOOpenrdf implements EntityDAO {

	public EntityDAOOpenrdf(Connector connector)
	{
		super(connector);
	}

	@Override
	public <T> T find(String id, Class<T> entityClass, String abox)
	{
		getConnection();
		
		StringBuilder sb = new StringBuilder();
		
		Class<?> currentClass = entityClass;
		
		int idCount = 0;
		
		sb
		.append(" SELECT DISTINCT  ?id ?property ?value \n")
		.append(" WHERE \n")
		.append(" { \n");
		
		while (currentClass != null)
		{
			for (Field field : currentClass.getDeclaredFields())
			{
				field.setAccessible(true);
				
				Property property = field.getAnnotation(Property.class);
				
				if (property == null)
					continue;
				
				sb
				.append(" 	optional \n")
				.append(" 	{ \n")
				.append("   	?id_" + idCount + " ?property ?value . \n")
				.append("   	BIND ((?id_" + idCount + ") AS ?id) \n")
				.append(" 	} \n");
			}
			
			currentClass = currentClass.getSuperclass();
			idCount++;
		}
		
		sb
		.append(" } \n");
		
		TupleQuery tupleQuery = prepareTupleQuery(getConnection(), sb.toString());
		
		tupleQuery.setBinding("id_0", createURI(id));
		
		Map<String, Map<String, List<String>>> instances = new HashMap<String, Map<String,List<String>>>();
		
        try
        {
			TupleQueryResult results = tupleQuery.evaluate();
			
			while (results.hasNext()) {

				BindingSet result = results.next();

				String currentId = getString("id", result);
				
				Map<String, List<String>> instance = instances.get(currentId);
				
				if (instance == null)
				{
					instance = new HashMap<String, List<String>>();
					instances.put(currentId, instance);
				}
				
				String property = getString("property", result);
				
				List<String> values = instance.get(property);
				
				if (values == null)
				{
					values = new ArrayList<String>();
					instance.put(property, values);
				}
				
				values.add(getString("value", result));
			}
		}
        catch (QueryEvaluationException e)
        {
			throw new TripleLinkException(e);
		}
		
		return EntityGeneretor.generate(id, instances, entityClass);
	}
	
	@Override
	public <T> T save(T entity, String abox)
	{
		QueryTL queryTL = InsertQueryBuilder.build(entity, abox, getConnector());
		
		executeUpDate(queryTL);
		
		return entity;
	}

	@Override
	public <T> void delete(T entity, String abox)
	{
		QueryTL queryTL = DeleteQueryBuilder.build(entity, abox, getConnector());
		
		executeUpDate(queryTL);
	}

	@Override
	public <T> T merge(T entity, String abox)
	{
		QueryTL queryTL = MergeQueryBuilder.build(entity, abox, getConnector());
		
		executeUpDate(queryTL);
		
		return entity;
	}
}
